/*
 * Copyright (c) 2007 Compl Yue Still, All Rights Reserved.
 */

package hbi.wire.java.host;

import hbi.java.util.DataCompat;
import hbi.wire.ProtocolError;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Date;

class TypedArray implements DataTag
{

    public Object getTagValue()
    {
        return content.getTagValue();
    }

    public void reset()
    {
        throw new RuntimeException("should never get called here");
    }

    private int dimension;

    private TypedArrayContent content;

    private final Class<?> expectedType;

    TypedArray(Class<?> expectedType)
    {
        this.expectedType = expectedType;
        this.dimension = 1;
        this.content = null;
    }

    public boolean processIncomingData(ByteBuffer buffer) throws IOException
    {
        if (content == null)
        {
            tag_scan: while (buffer.hasRemaining())
            {
                int typeTag = buffer.get() & 0xFF;
                switch (typeTag)
                {
                case 'T':
                    content = new TypedArrayContent(Boolean.TYPE, dimension,
                        new BoolElement());
                    break;
                case 'I':
                    content = new TypedArrayContent(Integer.TYPE, dimension,
                        new Int32());
                    break;
                case 'L':
                    content = new TypedArrayContent(Long.TYPE, dimension,
                        new Int64());
                    break;
                case 'D':
                    content = new TypedArrayContent(Double.TYPE, dimension,
                        new FP64());
                    break;
                case 'S':
                    content = new TypedArrayContent(String.class, dimension,
                        new UTF8Chunks(true));
                    break;
                case 'B':
                    content = new TypedArrayContent(new byte[0].getClass(),
                        dimension, new BinaryChunks(true));
                    break;
                case 'd':
                    content = new TypedArrayContent(Date.class, dimension,
                        new UTCDate());
                    break;
                case '[': // another nested dimension
                    dimension++;
                    if (dimension > 127)
                        throw new SecurityException(
                            "Banged with extreme deep array dimension!");
                    continue tag_scan;
                case 's':
                    throw new ProtocolError(
                        "Invalid array element type: Reader");
                case 'b':
                    throw new ProtocolError(
                        "Invalid array element type: InputStream");
                default:
                    throw new ProtocolError("Bad type tag: " + typeTag);
                }
                if (!DataCompat.isTypeCompatible(expectedType
                    .getComponentType(), content.componentType))
                    throw new ProtocolError(
                        "Incompatible array component type: "
                            + content.componentType.getCanonicalName()
                            + " for "
                            + expectedType.getComponentType()
                                .getCanonicalName());
                break tag_scan;
            }

            if (content == null) return false;
        }

        if (!buffer.hasRemaining()) return false;

        if (content.processIncomingData(buffer))
        {
            return true;
        }

        return false;
    }

}
